# -*- coding: utf-8 -*-
"""
用户业务逻辑层

负责用户相关的业务逻辑处理
"""
import json
import requests
import uuid
from typing import Dict, Any, Optional
from datetime import datetime, timedelta
from app.utils.jwt_utils import create_access_token, create_refresh_token, verify_token, get_user_id_from_token, JWTError
from app.repositories.user_repository import UserRepository, UserSessionRepository
from .config_service import config_service
from Crypto.Cipher import AES
import base64
import logging

logger = logging.getLogger(__name__)

class UserService:
    """用户业务逻辑类"""
    
    def __init__(self):
        self.user_repository = UserRepository()
        self.session_repo = UserSessionRepository()
        
        # 使用配置服务获取配置
        self.config_service = config_service
    
    @property
    def wechat_config(self) -> Dict[str, Any]:
        """获取微信配置"""
        return self.config_service.get_wechat_config()
    
    @property
    def jwt_config(self) -> Dict[str, Any]:
        """获取JWT配置"""
        return self.config_service.get_jwt_config()
    
    def wechat_login(self, js_code: str, encrypted_data: Optional[str] = None, 
                    iv: Optional[str] = None, client_ip: str = "unknown", 
                    user_info: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """微信小程序登录"""
        
        # 1. 通过 js_code 获取 session_key 和 openid
        session_info = self._get_wechat_session(js_code)
        if not session_info:
            raise ValueError("微信登录失败，无效的授权码")
        
        openid = session_info.get('openid')
        session_key = session_info.get('session_key')
        unionid = session_info.get('unionid')
        
        if not openid:
            raise ValueError("微信登录失败，获取用户信息失败")
        
        # 2. 查询用户是否已存在
        user = self.user_repository.find_by_wechat_openid(openid)
        
        # 3. 处理用户信息
        decrypted_user_info = {}
        if encrypted_data and iv and session_key:
            try:
                decrypted_user_info = self._decrypt_wechat_data(encrypted_data, iv, session_key)
            except Exception as e:
                print(f"解密用户信息失败: {e}")
                # 解密失败不影响登录，只是没有详细用户信息
        
        # 4. 合并用户信息（优先使用前端传递的信息）
        final_user_info = {}
        if user_info:
            final_user_info.update(user_info)
        if decrypted_user_info:
            # 如果前端没有提供某些信息，使用解密的信息补充
            for key, value in decrypted_user_info.items():
                if key not in final_user_info or not final_user_info[key]:
                    final_user_info[key] = value
        
        # 5. 处理用户数据
        if user:
            # 更新现有用户的微信信息
            wechat_data = {
                'session_key': session_key,
                'nickname': final_user_info.get('nickName', user.get('wechat_nickname', '微信用户')),
                'avatar_url': final_user_info.get('avatarUrl', user.get('wechat_avatar', ''))
            }
            self.user_repository.update_wechat_info(user['user_id'], wechat_data)
            user_id = user['user_id']
        else:
            # 创建新用户
            wechat_data = {
                'openid': openid,
                'unionid': unionid,
                'session_key': session_key,
                'nickname': final_user_info.get('nickName', '微信用户'),
                'avatar_url': final_user_info.get('avatarUrl', ''),
                'gender': final_user_info.get('gender', 0)
            }
            user_id = self.user_repository.create_wechat_user(wechat_data)
            if not user_id:
                raise ValueError("创建用户失败")
        
        # 6. 更新登录信息
        self.user_repository.update_login_info(user_id, client_ip)
        
        # 7. 生成访问令牌
        access_token = self._generate_access_token(user_id)
        refresh_token = self._generate_refresh_token(user_id)
        
        # 8. 创建会话记录
        session_data = {
            'user_id': user_id,
            'access_token': access_token,
            'refresh_token': refresh_token,
            'device_type': 'miniprogram',
            'client_ip': client_ip
        }
        session_id = self.session_repo.create_session(session_data)
        
        # 9. 获取最新用户信息
        updated_user = self.user_repository.find_by_id("user_id", user_id)
        
        if not updated_user:
            # 如果无法获取更新后的用户信息，使用默认值
            updated_user = {
                'user_id': user_id,
                'user_no': f'USER{user_id}',
                'nickname': final_user_info.get('nickName', '微信用户'),
                'avatar': final_user_info.get('avatarUrl', ''),
                'phone': '',
                'email': '',
                'wechat_nickname': final_user_info.get('nickName', '微信用户'),
                'wechat_avatar': final_user_info.get('avatarUrl', '')
            }
        
        return {
            "code": 200,
            "message": "登录成功",
            "data": {
                "user_id": user_id,
                "user_info": {
                    "user_id": updated_user.get('user_id'),
                    "user_no": updated_user.get('user_no'),
                    "nickname": updated_user.get('nickname'),
                    "avatar": updated_user.get('avatar'),
                    "phone": updated_user.get('phone'),
                    "email": updated_user.get('email'),
                    "wechat_nickname": updated_user.get('wechat_nickname'),
                    "wechat_avatar": updated_user.get('wechat_avatar')
                },
                "access_token": access_token,
                "refresh_token": refresh_token,
                "expires_in": self.jwt_config["access_token_expire_minutes"] * 60,
                "session_id": session_id
            }
        }
    
    def verify_token(self, token: str) -> Optional[Dict[str, Any]]:
        """验证令牌"""
        try:
            return verify_token(token)
        except JWTError:
            return None
        except Exception as e:
            logger.error(f"验证令牌失败: {str(e)}")
            return None
    
    def logout(self, access_token: str) -> bool:
        """用户登出"""
        session = self.session_repo.find_by_access_token(access_token)
        if session:
            return self.session_repo.deactivate_session(session['session_id'])
        return False
    
    def refresh_token(self, refresh_token: str) -> Optional[Dict[str, Any]]:
        """刷新访问令牌"""
        try:
            jwt_config = self.jwt_config
            # 验证刷新令牌
            payload = jwt["decode"](
                refresh_token, 
                jwt_config["secret_key"], 
                algorithms=[jwt_config["algorithm"]]
            )
            user_id = payload.get("sub")
            
            if not user_id:
                return None
            
            # 生成新的访问令牌
            new_access_token = self._generate_access_token(user_id)
            
            return {
                "access_token": new_access_token,
                "expires_in": jwt_config["access_token_expire_minutes"] * 60
            }
            
        except JWTError:
            return None
    
    def phone_login(self, phone: str, code: str, zone: str = "86", client_ip: str = None) -> Dict[str, Any]:
        """手机号登录"""
        try:
            # 验证验证码（这里简化处理，实际应该验证短信验证码）
            if not code or len(code) != 6:
                return {
                    'code': 400,
                    'message': '验证码格式错误',
                    'data': None
                }
            
            # 记录登录尝试
            logger.info(f"手机登录尝试: phone={phone}, zone={zone}, client_ip={client_ip}")
            
            # 查找用户
            user = self.user_repository.find_by_phone(phone)
            
            if not user:
                # 用户不存在，创建新用户
                user_id = f"U{int(uuid.uuid4().hex[:8], 16)}"
                user_data = {
                    'user_id': user_id,
                    'phone': phone,
                    'nickname': f'用户{phone[-4:]}',
                    'avatar': ''
                }
                
                created_user_id = self.user_repository.create_user(user_data)
                if not created_user_id:
                    return {
                        'code': 500,
                        'message': '创建用户失败',
                        'data': None
                    }
                
                # 重新获取用户信息
                user = self.user_repository.find_by_phone(phone)
            
            if not user:
                return {
                    'code': 500,
                    'message': '用户信息获取失败',
                    'data': None
                }
            
            # 确保用户ID是字符串
            user_id = str(user['user_id'])
            logger.info(f"准备生成JWT token，用户ID: {user_id}, 类型: {type(user_id)}")
            
            # 生成JWT token
            access_token = create_access_token(user_id)
            refresh_token = create_refresh_token(user_id)
            
            logger.info(f"手机登录成功: user_id={user_id}, phone={phone}")
            
            return {
                'code': 200,
                'message': '登录成功',
                'data': {
                    'user': {
                        'user_id': user_id,
                        'phone': user['phone'],
                        'nickname': user.get('nickname', ''),
                        'avatar': user.get('avatar', '')
                    },
                    'access_token': access_token,
                    'refresh_token': refresh_token
                }
            }
            
        except Exception as e:
            logger.error(f"手机登录失败: {str(e)}")
            import traceback
            logger.error(f"错误详情: {traceback.format_exc()}")
            return {
                'code': 500,
                'message': f'手机登录失败: {str(e)}',
                'data': None
            }
    
    def get_user_info(self, user_id: str) -> Dict[str, Any]:
        """获取用户信息"""
        try:
            user = self.user_repository.find_by_id(user_id)
            
            if not user:
                return {
                    'code': 404,
                    'message': '用户不存在',
                    'data': None
                }
            
            return {
                'code': 200,
                'message': '获取用户信息成功',
                'data': {
                    'user_id': user['user_id'],
                    'phone': user['phone'],
                    'nickname': user.get('nickname', ''),
                    'avatar': user.get('avatar', ''),
                    'create_time': user.get('create_time')
                }
            }
            
        except Exception as e:
            logger.error(f"获取用户信息失败: {str(e)}")
            return {
                'code': 500,
                'message': f'获取用户信息失败: {str(e)}',
                'data': None
            }
    
    def update_user_info(self, user_id: str, update_data: Dict) -> Dict[str, Any]:
        """更新用户信息"""
        try:
            success = self.user_repository.update_user(user_id, update_data)
            
            if not success:
                return {
                    'code': 500,
                    'message': '更新用户信息失败',
                    'data': None
                }
            
            return {
                'code': 200,
                'message': '更新用户信息成功',
                'data': None
            }
            
        except Exception as e:
            logger.error(f"更新用户信息失败: {str(e)}")
            return {
                'code': 500,
                'message': f'更新用户信息失败: {str(e)}',
                'data': None
            }
    
    def _get_wechat_session(self, js_code: str) -> Optional[Dict[str, Any]]:
        """获取微信会话信息"""
        wechat_config = self.wechat_config
        
        # 在开发环境中，直接返回模拟数据
        if wechat_config['app_id'] == "your_app_id":  # 配置未设置时使用模拟数据
            return self._get_mock_session(js_code)
        
        url = f"{wechat_config['api_base']}/sns/jscode2session"
        params = {
            'appid': wechat_config['app_id'],
            'secret': wechat_config['app_secret'],
            'js_code': js_code,
            'grant_type': 'authorization_code'
        }
        
        try:
            response = requests.get(url, params=params, timeout=10)
            result = response.json()
            
            if result.get('errcode'):
                print(f"微信API错误: {result}")
                # 失败时返回模拟数据
                return self._get_mock_session(js_code)
            
            return result
        except Exception as e:
            print(f"调用微信API失败: {e}")
            # 在开发环境中，可以返回模拟数据
            return self._get_mock_session(js_code)
    
    def _get_mock_session(self, js_code: str) -> Dict[str, Any]:
        """获取模拟会话信息（开发测试用）"""
        # 根据js_code生成固定的openid，便于测试
        import hashlib
        openid_hash = hashlib.md5(js_code.encode()).hexdigest()
        
        return {
            'openid': f'wx_openid_{openid_hash[:10]}',
            'session_key': f'session_key_{uuid.uuid4().hex[:16]}',
            'unionid': f'wx_unionid_{openid_hash[:12]}'
        }
    
    def _decrypt_wechat_data(self, encrypted_data: str, iv: str, session_key: str) -> Dict[str, Any]:
        """解密微信用户数据"""
        try:
            # 尝试使用pycryptodome
       
            
            # Base64解码
            encrypted_data = base64.b64decode(encrypted_data)
            iv = base64.b64decode(iv)
            session_key = base64.b64decode(session_key)
            
            # AES解密
            cipher = AES.new(session_key, AES.MODE_CBC, iv)
            decrypted = cipher.decrypt(encrypted_data)
            
            # 去除padding
            decrypted = decrypted[:-decrypted[-1]]
            
            # 解析JSON
            user_info = json.loads(decrypted.decode('utf-8'))
            return user_info
            
        except ImportError:
            print("pycryptodome未安装，跳过微信数据解密")
            # 返回默认用户信息
            return {
                'nickName': '微信用户',
                'avatarUrl': '',
                'gender': 0
            }
        except Exception as e:
            print(f"解密失败: {e}")
            # 返回默认用户信息
            return {
                'nickName': '微信用户',
                'avatarUrl': '',
                'gender': 0
            }
    
    def _generate_access_token(self, user_id: str) -> str:
        """生成访问令牌"""
        jwt_config = self.jwt_config
        now = datetime.utcnow()
        expire_timestamp = int((now + timedelta(minutes=jwt_config["access_token_expire_minutes"])).timestamp())
        payload = {
            "sub": user_id,
            "exp": expire_timestamp,
            "iat": int(now.timestamp()),
            "type": "access"
        }
        
        return jwt["encode"](
            payload, 
            jwt_config["secret_key"], 
            algorithm=jwt_config["algorithm"]
        )
    
    def _generate_refresh_token(self, user_id: str) -> str:
        """生成刷新令牌"""
        jwt_config = self.jwt_config
        now = datetime.utcnow()
        expire_timestamp = int((now + timedelta(days=jwt_config["refresh_token_expire_days"])).timestamp())
        payload = {
            "sub": user_id,
            "exp": expire_timestamp,
            "iat": int(now.timestamp()),
            "type": "refresh"
        }
        
        return jwt["encode"](
            payload, 
            jwt_config["secret_key"], 
            algorithm=jwt_config["algorithm"]
        ) 